#include "../src/IoComm.h"
#include "../src/Common.h"
#include "../src/Framework.h"
#include "../src/Uart4.h"

#include "string.h"
#include "stdio.h"
#include "Debug.h"

static bool IsCommValid;
IoCommRecPack IoCommRecPacket;
IoCommCmdPack IoCommCmdPacket;

static uint16_t IdxModLen(uint16_t idx);

extern void Timer1_Polled(void);
extern BOOL b1ms;

void IoComm_Init(void)
{
    IoRxHead = 0;
    IoRxTail = 0;
    IoTxHead = 0;
    IoTxTail = 0;

    IsCommValid = false;
}

bool IoComm_ChkAndClearPackValidFlag(void) 
{
    if (IsCommValid) 
    {
        IsCommValid = false;
        return true;
    }
    else
    {
        return false;
    }
}

void IoComm_BuildRecPack(void) 
{
    while (true) 
    {
        uint8_t rxLen;
        if (IoRxTail >= IoRxHead) 
        {
            rxLen = IoRxTail - IoRxHead;
        } 
        else 
        {
            rxLen = (IO_BUF_LEN - IoRxHead) + IoRxTail;
        }

        if (rxLen < 6)
        {
            return;
        }

        IoCommRecPacket.Members.PackHead = IoRxData[IoRxHead];
        if (IoCommRecPacket.Members.PackHead != 0xAA) 
        {
            IoRxHead = IdxModLen(IoRxHead + 1);
            continue;
        }

        IoCommRecPacket.Members.Cmd = IoRxData[IdxModLen(IoRxHead + 1)];
        if ((IoCommRecPacket.Members.Cmd <= (FRAME_CMD_MIN | FRAME_MASK_ACK)) || (IoCommRecPacket.Members.Cmd >= (FRAME_CMD_MAX | FRAME_MASK_ACK)))
        {
            IoRxHead = IdxModLen(IoRxHead + 1);
            continue;
        }

        IoCommRecPacket.Members.DataByteLength = IoRxData[IdxModLen(IoRxHead + 2)];
        if (IoCommRecPacket.Members.DataByteLength > 4) 
        {
            IoRxHead = IdxModLen(IoRxHead + 1);
            continue;
        }

        if (rxLen < IoCommRecPacket.Members.DataByteLength + 5) 
        {
            return;
        }

        int i;
        for (i = 0; i < IoCommRecPacket.Members.DataByteLength; i++) 
        {
            IoCommRecPacket.Members.Data[i] = IoRxData[IdxModLen(IoRxHead + 3 + i)];
        }

        IoCommRecPacket.Members.Crc = (IoRxData[IdxModLen(IoRxHead + 2 + IoCommRecPacket.Members.DataByteLength + 2)] << 8) | IoRxData[IdxModLen(IoRxHead + 2 + IoCommRecPacket.Members.DataByteLength + 1)];
        uint16_t calCrc = Crc_Fun(&IoCommRecPacket.Members.Cmd, IoCommRecPacket.Members.DataByteLength + 2, 0);
        if (calCrc != IoCommRecPacket.Members.Crc)
        {
            IoRxHead = IdxModLen(IoRxHead + 1);
            continue;
        }

        IsCommValid = true;

        IoRxHead = IdxModLen(IoRxHead + IoCommRecPacket.Members.DataByteLength + 5);
        break;
    }
}

static uint16_t IdxModLen(uint16_t idx)
{
    return idx & (IO_BUF_LEN - 1);
}

void IoComm_FillTxBytesWithCmdPack(void)    /* IO data fill */
{
    IoComm_PutByteInTxBuf(IoCommCmdPacket.Members.PackHead, 0);
    IoComm_PutByteInTxBuf(IoCommCmdPacket.Members.Cmd, 1);
    IoComm_PutByteInTxBuf(IoCommCmdPacket.Members.DataByteLength, 2);

    uint8_t i;
    for (i = 0; i < IoCommCmdPacket.Members.DataByteLength; i++)
    {
        IoComm_PutByteInTxBuf(IoCommCmdPacket.Members.Data[i], 3 + i);
    }

    IoComm_PutByteInTxBuf(IoCommCmdPacket.Members.Crc, 3 + IoCommCmdPacket.Members.DataByteLength);
    IoComm_PutByteInTxBuf(IoCommCmdPacket.Members.Crc >> 8, 3 + IoCommCmdPacket.Members.DataByteLength + 1);

    IoTxTail = IdxModLen(IoTxTail + 5 + IoCommCmdPacket.Members.DataByteLength);
}

void IoComm_PutByteInTxBuf(uint8_t byte, uint16_t offset) 
{
    IoTxData[IdxModLen(IoTxTail + offset)] = byte;
}

void IoCommEnterBoot(void)
{
    uint8_t buf[5];
    buf[0] = 0x61;
    buf[1] = 0x00;
    buf[2] = 0x00;
    uint16_t crc = CRC16_Chk(buf, 3);
    buf[3] = crc >> 8;
    buf[4] = crc;

    int i;
    for (i = 0; i < 1; i++) 
    {
        int k;
        for (k = 0; k < 5; k++) 
        {
            IoComm_PutByteInTxBuf(buf[k], k);
        }    
        IoTxTail = IdxModLen(IoTxTail + 5);
    }
}

void IOcmd_test_spi(uint32_t data)
{
     uint32_t buf[5];
//                buf[0] = data;
//                buf[1] = data>>8;
//                buf[2] = data>>16;
//                buf[3] = data>>24;
//                buf[4] = 1;
                buf[0] = data;
                buf[1] = data;
                buf[2] = data;
                buf[3] = data;
                buf[4] = 1;
                int i;
                for (i = 0; i < 1; i++) 
                {
                    int k;
                    for (k = 0; k < 5; k++) 
                    {
                        IoComm_PutByteInTxBuf(buf[k], k);
                    }    
                    IoTxTail = IdxModLen(IoTxTail + 5);
                }
    IoComm_RxTx();
}